/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Parser;

import java.util.ArrayList;
import lowlevel.BasicBlock;
import lowlevel.CodeItem;
import lowlevel.Data;
import lowlevel.FuncParam;
import lowlevel.Function;
import scanner.*;
/**
 *
 * @author Fabulous
 */
public class Fundecl extends Decl{
    private ArrayList<Param> params;
    private CompoundStmt compoundStmt;
    public Fundecl(Identifier idToken, Token.TokenType typeToken){
        super(idToken, typeToken);
        params = new ArrayList<>();
    }
    public void addParam(Param p){
        params.add(p);
    }
    public void setCompoundStmt(CompoundStmt c){
        compoundStmt = c;
    }

    @Override
    void print(String indent) {
        CMinusParser.oFile.println(indent + "FundDecl:");
        
        if(this.type == Token.TokenType.INT_TOKEN){
            CMinusParser.oFile.println(indent + "  int");
        }
        else{
            CMinusParser.oFile.println(indent + "  void");
        }
        this.id.print(indent + "  ");
        
        CMinusParser.oFile.println(indent + "  Params:");
        if(params == null || params.size() == 0){
            CMinusParser.oFile.println(indent + "    null");
        }
        else{
            for(int i = 0; i < params.size(); i++){
                params.get(i).print(indent + "    ");
            }
        }
        
        compoundStmt.print(indent + "  ");
        CMinusParser.oFile.flush();
    }
    @Override
    public CodeItem genLLCode() {  
        Function func;
        FuncParam llParams = null;
        BasicBlock codeBlock;
        
        if(this.type == Token.TokenType.INT_TOKEN){
            func = new Function(Data.TYPE_INT, id.idName, llParams);
        } else {
            func = new Function(Data.TYPE_VOID, id.idName, llParams);
        }
        
        if(this.params.size() > 0){
            llParams = getLLParams(func);
        }
        func.setFirstParam(llParams);
        
        func.createBlock0();
        func.setCurrBlock(func.getLastBlock());
        
        codeBlock = new BasicBlock(func);
        func.appendToCurrentBlock(codeBlock);
        func.setCurrBlock(codeBlock);
        
        //call genLLCode on compound statement
        compoundStmt.genLLCode(func);
        
        //if(func.)
        //generate return block before you append unconnected block.
        BasicBlock retBlock = func.getReturnBlock();
        func.appendToCurrentBlock(retBlock);
        func.setCurrBlock(retBlock);
        
        BasicBlock firstUnconnected = func.getFirstUnconnectedBlock();
        if(firstUnconnected != null){
            func.appendToCurrentBlock(firstUnconnected);
        }
       
        return func;
    }
    
    private FuncParam getLLParams(Function func){
        FuncParam firstP = null;
        FuncParam lastP = null;

        for(Param p : params){
            FuncParam currP = new FuncParam(Data.TYPE_INT, p.id.idName);
            func.getTable().put(p.id.idName, func.getNewRegNum());
            if(lastP != null){
                lastP.setNextParam(currP);
                if(lastP == firstP){
                    firstP.setNextParam(currP);
                }
            } else {
                firstP = currP;
            }
            lastP = currP;
        }
        
        return firstP;
    }
}
